<style>
    body {
    padding: .2rem;
    display: grid;
    grid-template-areas: "control  log";
    }

    .control {
    grid-area: control;
    }

    .event-log {
    grid-area: log;
    }

    .event-log-contents {
    resize: none;
    }

    label, button {
    display: block;
    }

    input[type="text"] {
    margin: .5rem 0;
    }

    kbd {
    border-radius: 3px;
    padding: 1px 2px 0;
    border: 1px solid black;
    }
</style>
<div class="control">
<label for="name">On macOS, click in the textbox below,<br> then type <kbd>option</kbd> + <kbd>`</kbd>, then <kbd>a</kbd>:</label>
<input type="text" id="example" name="example">
</div>

<div class="event-log">
<label>Event log:</label>
<textarea readonly class="event-log-contents" rows="8" cols="25"></textarea>
<button class="clear-log">Clear</button>
</div>

<script type="text/javascript">
    const inputElement = document.querySelector('input[type="text"]');
    const log = document.querySelector('.event-log-contents');
    const clearLog = document.querySelector('.clear-log');

    clearLog.addEventListener('click', () => {
        log.textContent = '';
    });

    function handleEvent(event) {
        log.textContent = log.textContent + `${event.type}: ${event.data}\n`;
    }

    function handleChange(event) {
        log.textContent = log.textContent + `${event.type}: ${event.target.value}\n`
    }

    inputElement.addEventListener('compositionstart', handleEvent);
    inputElement.addEventListener('change', handleChange);
    inputElement.addEventListener('compositionupdate', handleEvent);
    inputElement.addEventListener('compositionend', handleEvent);
</script>